#include "cola.h"
#include <stdlib.h>


typedef struct _nodo {
		void* dato;
		struct _nodo *prox;
} nodo_t;


nodo_t* crear_nodo(void* dato){

	nodo_t* nodo = malloc(sizeof(nodo_t));
	if (nodo == NULL) return NULL;
	
	nodo->dato = dato;
	nodo->prox = NULL;
	return nodo;
}

struct cola {
	nodo_t *prim;
	nodo_t* ult;	// Se utiliza esta variable para no tener que
					// recorrer toda la cola para agregar un elemento
};

cola_t* cola_crear(){

	cola_t* nueva_cola = malloc(sizeof(cola_t));
	if ((nueva_cola) == NULL) return NULL;

	nueva_cola->prim = nueva_cola->ult = NULL;
	return nueva_cola;
}

void cola_destruir(cola_t *cola, void destruir_dato(void*, void*), void* extra){
	if (cola != NULL){
		nodo_t* actual;

		while (cola->prim != NULL){
			actual = cola->prim;
					cola->prim = (cola->prim)->prox;
			if (destruir_dato) destruir_dato(actual->dato, extra);
			free(actual);
			}
		free(cola);
	}
}

bool cola_esta_vacia(const cola_t *cola){
	if (cola == NULL) return true;
	if (cola->prim == NULL) return true;
	return false;
}

bool cola_encolar(cola_t *cola, void* valor){
	if (cola == NULL) return false;
	nodo_t* nuevo_elem = crear_nodo(valor);
	if (nuevo_elem == NULL) return false;

	if (cola_esta_vacia(cola)){
		cola->prim = nuevo_elem;
	}else{
		cola->ult->prox = nuevo_elem;
	}
	
	cola->ult = nuevo_elem;
	return true;
}

void* cola_ver_primero(const cola_t *cola){

	if (cola_esta_vacia(cola)) return NULL;
	return cola->prim->dato;
}

void* cola_desencolar(cola_t *cola){

	if (cola_esta_vacia(cola)) return NULL;

	void* dato = cola_ver_primero(cola);	// Guarda el dato del nodo
	
	nodo_t* primer_elemento = cola->prim;	// Y su direccion
	
	// Adelanta un lugar (si hay solo un elemento queda NULL)
	cola->prim = cola->prim->prox;	
	if (cola->prim == NULL) cola->ult = NULL;

	free(primer_elemento);	// Elimina el elemento que se desencolo
	
	return dato;
}
